package cn.south.campus.admin.sys.service.impl;

import cn.south.campus.admin.sys.mapper.SysRoleMapper;
import cn.south.campus.admin.sys.mapper.SysUserMapper;
import cn.south.campus.admin.sys.model.entity.SysMenu;
import cn.south.campus.admin.sys.model.entity.SysRole;
import cn.south.campus.admin.sys.model.entity.SysUser;
import cn.south.campus.admin.sys.model.enums.SysRespEnums;
import cn.south.campus.admin.sys.model.req.SysRoleReq;
import cn.south.campus.admin.sys.model.vo.SysRoleVo;
import cn.south.campus.admin.sys.service.SysMenuService;
import cn.south.campus.admin.sys.service.SysRoleMenuService;
import cn.south.campus.admin.sys.service.SysRoleService;
import cn.south.campus.common.model.enums.CommonEnums;
import cn.south.campus.common.utils.AssertUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;


/**
 * 实现层
 *
 * @Author wq
 * @Date 2020-12-15
 **/
@Service
@AllArgsConstructor
@Transactional(rollbackFor = RuntimeException.class)
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements SysRoleService {


    private final SysMenuService sysMenuService;

    private final SysRoleMapper sysRoleMapper;

    private final SysUserMapper sysUserMapper;

    private final SysRoleMenuService sysRoleMenuService;

    @Override
    public IPage<SysRoleVo> page(SysRoleReq req) {
        LambdaQueryWrapper<SysRole> wrapper = new LambdaQueryWrapper<SysRole>()
                .like(StringUtils.hasText(req.getRoleName()), SysRole::getRoleName, req.getRoleName())
                .orderByDesc(SysRole::getUpdateTime);
        Page<SysRole> rolePage = sysRoleMapper.selectPage(req.getPageDto(), wrapper);
        return rolePage.convert(SysRoleVo::convert);
    }

    @Override
    public void add(SysRoleVo vo) {
        //保存角色
        SysRole role = new SysRole();
        role.setRoleDesc(vo.getRoleDesc());
        role.setRoleName(vo.getRoleName());
        sysRoleMapper.insert(role);
        //保存角色ID对应的菜单ID
        Long roleId = role.getId();
        Set<Long> menuIds = vo.getMenuIds();
        //保存角色菜单中间表
        sysRoleMenuService.saveRelation(roleId, menuIds);
    }

    @Override
    public void updateRole(SysRoleVo vo) {
        SysRole sysRole = getById(vo.getId());
        AssertUtils.isNotNull(sysRole, CommonEnums.DATA_HAS_NOT_ERROR);
        sysRole.setRoleDesc(vo.getRoleDesc());
        sysRole.setRoleName(vo.getRoleName());
        sysRoleMapper.updateById(sysRole);
        //删除角色删除中间表
        sysRoleMenuService.delRelation(vo.getId());
        Set<Long> ids = buildMenuIds(vo.getMenuIds());
        sysRoleMenuService.saveRelation(vo.getId(), ids);
    }

    @Override
    public SysRoleVo detail(Long id) {
        SysRole role = getById(id);
        SysRoleVo sysRoleVo = SysRoleVo.convert(role);
        List<Long> relation = sysRoleMenuService.findRelation(id);
        Set<Long> ids = buildDetailMenuIds(relation);
        sysRoleVo.setMenuIds(ids);
        return sysRoleVo;
    }

    private Set<Long> buildDetailMenuIds(List<Long> menuIds) {
        Set<Long> ids = new HashSet<>();
        for (Long menuId : menuIds) {
            boolean b = sysMenuService.isExistChildren(menuId);
            if (b) {
                continue;
            }
            ids.add(menuId);
        }
        return ids;
    }

    @Override
    public void delete(Long id) {
        Long count = sysUserMapper.selectCount(new LambdaQueryWrapper<SysUser>().eq(SysUser::getRoleId, id));
        AssertUtils.isLtE(count, 1L, SysRespEnums.ROLE_HAS_USER_ERROR);
        baseMapper.deleteById(id);
        //删除角色菜单中间表
        sysRoleMenuService.delRelation(id);

    }

    @Override
    public List<SysRoleVo> getList() {
        return list().stream().map(SysRoleVo::convert).collect(Collectors.toList());
    }

    /**
     * 选择了子类的菜单,父级的菜单也默认选上
     *
     * @param menuIds 菜单集合
     * @return 新的ID集合
     */
    private Set<Long> buildMenuIds(Set<Long> menuIds) {
        Set<Long> ids = new HashSet<>();
        for (Long menuId : menuIds) {
            //查询当前选中菜单
            SysMenu menu = sysMenuService.getById(menuId);
            //如果当前菜单不是第一级菜单 把他父菜单加进去
            if (!menu.getParentId().equals(0L)) {
                ids.add(menu.getParentId());
            }
            //把当前菜单加进去
            ids.add(menuId);
        }
        return ids;
    }

}
